package com.casework.auth

import grails.util.Environment
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

class AuthUserController {

    def springSecurityService
    def mailService

    static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

    def changePassword = {
        AuthUser authUser = AuthUser.get(params.id)

        if(params.password){
            String password = springSecurityService.encodePassword(params.password)
            authUser.password = password
            authUser.save()
            flash.message = 'Password has been updated'
        }

        render view: 'changePassword', model: [authUserInstance: authUser]
    }

    def index = {
        redirect(action: "list", params: params)
    }

    def list = {
        params.max = Math.min(params.max ? params.int('max') : 10, 100)
        [authUserInstanceList: AuthUser.list(params), authUserInstanceTotal: AuthUser.count()]
    }

    def create = {
        def authUserInstance = new AuthUser(password: generatePassword(15))
        authUserInstance.properties = params
        return [authUserInstance: authUserInstance, companyId: params.companyId]
    }

    def save = {

        String password = springSecurityService.encodePassword(params.password)
        def authUserInstance = new AuthUser(email: params.email, username: params.username,
                password: password, accountLocked: false, enabled: true)

        Company company = Company.get(params.companyId)
        if (company) {
            company.addToEmployees(authUserInstance).save()
        }

        if (authUserInstance.save(flush: true)) {
            flash.message = "${message(code: 'default.created.message', args: [message(code: 'authUser.label', default: 'AuthUser'), authUserInstance])}"
            flash.email = "An email was sent to ${authUserInstance.email} with a username= ${authUserInstance.username} and password= ${params.password}."

            if (params.roleAdmin) {
                def authRole = Role.findByAuthority('ROLE_ADMIN')
                AuthUserRole.create(authUserInstance, authRole, true)
            }

            if (params.roleEditor) {
                def userRole = Role.findByAuthority('ROLE_USER')
                AuthUserRole.create(authUserInstance, userRole, true)
            }

            def conf = SpringSecurityUtils.securityConfig
            def bodyOfEmail = conf.ui.register.emailBody
            bodyOfEmail = bodyOfEmail.replace('<username>', authUserInstance.username)
            bodyOfEmail = bodyOfEmail.replace('<password>', params.password)

            mailService.sendMail {
                to authUserInstance.email
                from conf.ui.register.emailFrom
                subject conf.ui.register.emailSubject
                body bodyOfEmail.toString()
            }


            redirect(action: "show", controller: 'company', id: company.id)
        }
        else {
            render(view: "create", model: [authUserInstance: authUserInstance])
        }
    }

    def show = {
        def authUserInstance = AuthUser.get(params.id)
        if (!authUserInstance) {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'authUser.label', default: 'AuthUser'), params.id])}"
            redirect(action: "list")
        }
        else {
            [authUserInstance: authUserInstance]
        }
    }

    def edit = {
        def authUserInstance = AuthUser.get(params.id)
        if (!authUserInstance) {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'authUser.label', default: 'AuthUser'), params.id])}"
            redirect(action: "list")
        }
        else {
            return [authUserInstance: authUserInstance]
        }
    }

    def update = {
        def authUserInstance = AuthUser.get(params.id)
        if (authUserInstance) {
            if (params.version) {
                def version = params.version.toLong()
                if (authUserInstance.version > version) {

                    authUserInstance.errors.rejectValue("version", "default.optimistic.locking.failure", [message(code: 'authUser.label', default: 'AuthUser')] as Object[], "Another user has updated this AuthUser while you were editing")
                    render(view: "edit", model: [authUserInstance: authUserInstance])
                    return
                }
            }
            authUserInstance.properties = params
            if (!authUserInstance.hasErrors() && authUserInstance.save(flush: true)) {
                updateRoles(authUserInstance)

                flash.message = "User ${authUserInstance} updated"
                redirect(action: "show", id: authUserInstance.company.id, controller: 'company')
            }
            else {
                render(view: "edit", model: [authUserInstance: authUserInstance])
            }
        }
        else {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'authUser.label', default: 'AuthUser'), params.id])}"
            redirect(action: "list")
        }
    }


    private updateRoles(AuthUser authUserInstance) {
        removeUserRoleWhenNonePassedInAndAlreadyAssigned(authUserInstance)
        removeAdminRoleWhenNonePassedInAndAlreadyAssigned(authUserInstance)
        addAdminRoleWhenPassedInAndNotAlreadyAssigned(authUserInstance)
        addUserRoleWhenPassedInAndNotAlreadyAssigned(authUserInstance)
    }

    private def removeAdminRoleWhenNonePassedInAndAlreadyAssigned(AuthUser authUserInstance){
        if (!params.roleAdmin && authUserInstance.admin) {
            def adminRole = Role.findByAuthority('ROLE_ADMIN')
            AuthUserRole.remove(authUserInstance, adminRole, true)
        }
    }

    private def removeUserRoleWhenNonePassedInAndAlreadyAssigned(AuthUser authUserInstance) {
        if (!params.roleEditor && authUserInstance.user) {
            def userRole = Role.findByAuthority('ROLE_USER')
            AuthUserRole.remove(authUserInstance, userRole, true)
        }
    }

    private def addUserRoleWhenPassedInAndNotAlreadyAssigned(AuthUser authUserInstance) {
        if (params.roleEditor && !authUserInstance.user) {
            def userRole = Role.findByAuthority('ROLE_USER')
            AuthUserRole.create(authUserInstance, userRole, true)
        }
    }

    private def addAdminRoleWhenPassedInAndNotAlreadyAssigned(AuthUser authUserInstance) {
        if (params.roleAdmin && !authUserInstance.admin) {
            def authRole = Role.findByAuthority('ROLE_ADMIN')
            AuthUserRole.create(authUserInstance, authRole, true)
        }
    }


    def delete = {
        def authUserInstance = AuthUser.get(params.id)
        if (authUserInstance) {
            try {
                authUserInstance.delete(flush: true)
                flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'authUser.label', default: 'AuthUser'), params.id])}"
                redirect(action: "list")
            }
            catch (org.springframework.dao.DataIntegrityViolationException e) {
                flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'authUser.label', default: 'AuthUser'), params.id])}"
                redirect(action: "show", id: params.id)
            }
        }
        else {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'authUser.label', default: 'AuthUser'), params.id])}"
            redirect(action: "list")
        }
    }

    private String generatePassword(length) {
        // Get a list of valid chard (strip out the confusing ones when using rubbish fonts)
        def allChars = ['A'..'Z', 'a'..'z', '0'..'9'].flatten() - ['O', '0', 'l', '1', 'I']

        if (Environment.currentEnvironment == Environment.DEVELOPMENT) {
            return 'password1234'
        }
        return (0..<length).collect { allChars[new Random().nextInt(allChars.size())] }.join()
    }

}
